package com.netease.financial.module.web;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;

import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import com.netease.financial.R;
import com.netease.financial.base.customerservice.CustomerServiceHelper;
import com.netease.financial.base.lockpattern.LockPatternHelper;
import com.netease.financial.base.login.LoginActivity;
import com.netease.financial.base.photo.PhotoSelectionHandler;
import com.netease.financial.base.photo.PhotoUtils;
import com.netease.financial.base.share.dialog.SharePanelDialog;
import com.netease.financial.base.share.model.ShareHolder;
import com.netease.financial.base.web.JSBridge;
import com.netease.financial.base.web.JSInterface;
import com.netease.financial.common.util.NfsLog;
import com.netease.financial.common.util.preferences.BadgePreferencesHelper;
import com.netease.financial.ui.fragment.TabFragment;

import org.json.JSONObject;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import butterknife.Bind;
import butterknife.ButterKnife;

/**
 * A simple {@link Fragment} subclass.
 * Activities that contain this fragment must implement the
 * {@link OnFragmentInteractionListener} interface
 * to handle interaction events.
 */
public abstract class WebViewTabFragment extends TabFragment {

    private static final String TAG = WebViewTabFragment.class.getSimpleName();

    private static final int REQUEST_CODE_RESET_LOCK_PATTERN_AUTHENTICATION = 1;
    private static final int REQUEST_CODE_CREATE_LOCK_PATTERN = 2;
    private static final int REQUEST_CODE_RESET_LOCK_PATTERN = 3;
    private static final int REQUEST_CODE_LOGIN = 4;

    private Map<String, ActivityResultHandler> mActivityResultHandlerMap = new HashMap<>();
    private OnFragmentInteractionListener mListener;
    private WebViewHelper mWebViewHelper;
    private Uri mCurrentPhotoUri;
    private ShareHolder mShareHolder;

    private JSBridge.Command mOnMenuShareCommand;

    public WebViewTabFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    // 获取初始的web url
    public abstract String getInitialPageUrl();

    @Bind(R.id.webView)
    WebView webView;

    public WebView getWebView() {
        return webView;
    }

    public WebViewHelper getWebViewHelper() {
        return mWebViewHelper;
    }

    public OnFragmentInteractionListener getFragmentInteractionListener() {
        return mListener;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_webview, container, false);
        ButterKnife.bind(this, rootView);

        init();

        return rootView;
    }

    private void init() {
        NfsLog.d(TAG, "init.fragmentTag:" + getTag());
        mWebViewHelper = new WebViewHelper(getActivity(), this, webView, getInitialPageUrl());
        mWebViewHelper.setOnFragmentInteractionListener(mListener);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        bindPhotoHandler();
        bindWebActionListeners();
    }

    @Override
    public void onStart() {
        super.onStart();
        CustomerServiceHelper.trackUserAccess(webView.getUrl(), webView.getTitle());
        CustomerServiceHelper.saveCurrentWebPageInfo(webView.getUrl(), webView.getTitle());
    }

    @Override
    public void onStop() {
        super.onStop();
        CustomerServiceHelper.removeCurrentWebPageInfo();
    }

    public void clearWebViewCache() {
        webView.clearCache(true);
    }

    private void bindPhotoHandler() {
        PhotoHandler photoHandler = new PhotoHandler(getActivity());
        mWebViewHelper.addWebActionListener(JSInterface.REQUEST_JS_CHOOSE_IMAGE,
                (PhotoHandler.PhotoEditorListener) photoHandler.getListener());
    }

    private void bindWebActionListeners() {
        LoginHandler loginHandler = new LoginHandler();
        mWebViewHelper.addWebActionListener(JSInterface.REQUEST_JS_NAVIGATE_TO_LOGIN_SCREEN, loginHandler);

        LockPatternHandler lockPatternHandler = new LockPatternHandler();
        mWebViewHelper.addWebActionListener(JSInterface.REQUEST_JS_SHOW_LOCK_PATTERN_CREATE_SCREEN, lockPatternHandler);
        mWebViewHelper.addWebActionListener(JSInterface.REQUEST_JS_SHOW_LOCK_PATTERN_RESET_SCREEN, lockPatternHandler);
        mWebViewHelper.addWebActionListener(JSInterface.REQUEST_JS_SHOW_OPTION_MENU, new JSInterface.WebActionListener() {
            @Override
            public void onRequest(JSBridge.Command cmd) {
                if (mListener != null) {
                    mListener.showOptionMenu();
                }
            }
        });
        mWebViewHelper.addWebActionListener(JSInterface.REQUEST_JS_HIDE_OPTION_MENU, new JSInterface.WebActionListener() {
            @Override
            public void onRequest(JSBridge.Command cmd) {
                if (mListener != null) {
                    mListener.hideOptionMenu();
                }
            }
        });
        mWebViewHelper.addWebActionListener(JSInterface.REQUEST_JS_ON_MENU_SHARE, new JSInterface.WebActionListener() {
            @Override
            public void onRequest(JSBridge.Command cmd) {
                mOnMenuShareCommand = cmd;
                mShareHolder = ShareHolder.createShareHolderFromJson(cmd.getParams());
            }
        });
        mWebViewHelper.addWebActionListener(JSInterface.REQUEST_JS_SET_UNREAD_PRIVATE_MESSAGE_COUNT, new JSInterface.WebActionListener() {
            @Override
            public void onRequest(JSBridge.Command cmd) {
                handleSetUnreadMessageCountEvent(cmd);
            }
        });
        mWebViewHelper.addWebActionListener(JSInterface.REQUEST_JS_SET_TITLE, new JSInterface.WebActionListener() {
            @Override
            public void onRequest(JSBridge.Command cmd) {
                if (mListener != null) {
                    mListener.setNavigationTitle(cmd.getParams().optString(JSInterface.PARAM_JS_TITLE));
                }
            }
        });
    }

    private void handleSetUnreadMessageCountEvent(JSBridge.Command command) {
        JSONObject jsonObject = command.getParams();
        if (jsonObject.has(JSInterface.PARAM_JS_ACCOUNT_UNREAD_MESSAGE_COUNT)) {
            int count = jsonObject.optInt(JSInterface.PARAM_JS_ACCOUNT_UNREAD_MESSAGE_COUNT);
            BadgePreferencesHelper.setUnreadPrivateMessageCount(count);
            refreshTabBadgeView();
        }
    }

    @Override
    public void onAttach(Context context) {
        NfsLog.d(TAG, "onAttach.fragmentTag:" + getTag());
        super.onAttach(context);
        try {
            mListener = (OnFragmentInteractionListener) context;
            if (mWebViewHelper != null) {
                mWebViewHelper.setOnFragmentInteractionListener(mListener);
            }
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString() + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
        if (mWebViewHelper != null) {
            mWebViewHelper.setOnFragmentInteractionListener(null);
        }
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        mWebViewHelper.onHiddenChanged(hidden);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        ActivityResultHandler handler = getActivityResultHandler(requestCode);
        if (handler != null && handler.handleActivityResult(requestCode, resultCode, data)) {
            removeActivityResultHandler(requestCode);
            return;
        }

        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public boolean onCustomViewItemSelected(View view) {
        switch (view.getId()) {
            case R.id.btn_share:
                showBottomSharePanel();
                break;
            case R.id.tv_nav_back:
                handleGoBackEvent();
                break;
            case R.id.tv_title:
                break;
            default:
                break;
        }
        return super.onCustomViewItemSelected(view);
    }

    private void handleGoBackEvent() {
        mWebViewHelper.handleGoBackEvent();
    }

    private void showBottomSharePanel() {
        if (isVisible()) {
            if (mShareHolder == null) {
                mShareHolder = new ShareHolder();
            }

            if (TextUtils.isEmpty(mShareHolder.webUrl)) {
                mShareHolder.title = webView.getTitle();
                mShareHolder.description = webView.getContentDescription().toString();
                mShareHolder.webUrl = webView.getUrl();
            }

            SharePanelDialog dialog = new SharePanelDialog(getActivity());
            dialog.setCommand(mOnMenuShareCommand);
            dialog.setShareInfo(mShareHolder);
            dialog.show();
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        ButterKnife.unbind(this);
    }

    public interface ActivityResultHandler {
        boolean handleActivityResult(int requestCode, int resultCode, Intent data);
    }

    private void saveActivityResultHandler(int requestCode, ActivityResultHandler listener) {
        mActivityResultHandlerMap.put("request_code_" + requestCode, listener);
    }

    private ActivityResultHandler getActivityResultHandler(int requestCode) {
        return mActivityResultHandlerMap.get("request_code_" + requestCode);
    }

    private void removeActivityResultHandler(int requestCode) {
        mActivityResultHandlerMap.remove("request_code_" + requestCode);
    }

    private final class LoginHandler implements ActivityResultHandler, JSInterface.WebActionListener {
        private JSBridge.Command mLoginCommand;

        @Override
        public void onRequest(JSBridge.Command cmd) {
            if (JSInterface.REQUEST_JS_NAVIGATE_TO_LOGIN_SCREEN.equals(cmd.getName())) {
                mLoginCommand = cmd;
                saveActivityResultHandler(REQUEST_CODE_LOGIN, this);
                getNavigator().navigateToLoginScreen(WebViewTabFragment.this, REQUEST_CODE_LOGIN);
            }
        }

        @Override
        public boolean handleActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == REQUEST_CODE_LOGIN) {
                if (mLoginCommand != null) {
                    String result = getResult(resultCode);
                    if (resultCode == Activity.RESULT_OK) {
                        Bundle bundle = new Bundle();
                        bundle.putString(JSInterface.PARAM_NATIVE_ACCOUNT_RESULT, result);
                        bundle.putString(JSInterface.PARAM_NATIVE_ACCOUNT_CLIENT_ID, data.getStringExtra(LoginActivity.INTENT_EXTRA_KEY_CLIENT_ID));
                        bundle.putString(JSInterface.PARAM_NATIVE_ACCOUNT_ACCESS_TOKEN, data.getStringExtra(LoginActivity.INTENT_EXTRA_KEY_ACCESS_TOKEN));
                        bundle.putString(JSInterface.PARAM_NATIVE_ACCOUNT_USER_ID, data.getStringExtra(LoginActivity.INTENT_EXTRA_KEY_USER_ID));
                        mLoginCommand.setResult(bundle);
                    } else {
                        mLoginCommand.setResult(JSInterface.PARAM_NATIVE_ACCOUNT_RESULT, result);
                    }
                }
                return true;
            }
            return false;
        }
    }

    private final class LockPatternHandler implements JSInterface.WebActionListener, ActivityResultHandler {
        private JSBridge.Command mCreateLockPatternCommand;
        private JSBridge.Command mResetLockPatternCommand;

        @Override
        public void onRequest(JSBridge.Command cmd) {
            if (JSInterface.REQUEST_JS_SHOW_LOCK_PATTERN_CREATE_SCREEN.equals(cmd.getName())) {
                mCreateLockPatternCommand = cmd;
                String userId = cmd.getParams().optString(JSInterface.PARAM_JS_LOCK_PATTERN_USER_ID);
                if (!LockPatternHelper.isLockPatternExistsForUser(userId)) {
                    saveActivityResultHandler(REQUEST_CODE_CREATE_LOCK_PATTERN, this);
                    getNavigator().navigateToCreateLockPatternScreen(WebViewTabFragment.this, userId, REQUEST_CODE_CREATE_LOCK_PATTERN);
                }
            } else if (JSInterface.REQUEST_JS_SHOW_LOCK_PATTERN_RESET_SCREEN.equals(cmd.getName())) {
                mResetLockPatternCommand = cmd;
                String clientId = cmd.getParams().optString(JSInterface.PARAM_JS_LOCK_PATTERN_CLIENT_ID);
                String headPortraitUrl = cmd.getParams().optString(JSInterface.PARAM_JS_LOCK_PATTERN_HEAD_PORTRAIT_URL);
                String userId = cmd.getParams().optString(JSInterface.PARAM_JS_LOCK_PATTERN_USER_ID);
                String nextTip = getString(R.string.next_prompt);

                saveActivityResultHandler(REQUEST_CODE_RESET_LOCK_PATTERN_AUTHENTICATION, this);
                getNavigator().navigateToAuthenticationScreen(WebViewTabFragment.this, clientId, headPortraitUrl, userId, nextTip, REQUEST_CODE_RESET_LOCK_PATTERN_AUTHENTICATION);
            }
        }

        @Override
        public boolean handleActivityResult(int requestCode, int resultCode, Intent data) {
            switch (requestCode) {
                case REQUEST_CODE_CREATE_LOCK_PATTERN:
                    if (mCreateLockPatternCommand != null) {
                        mCreateLockPatternCommand.setResult(JSInterface.PARAM_NATIVE_LOCK_PATTERN_RESULT, getResult(resultCode));
                    }
                    return true;
                case REQUEST_CODE_RESET_LOCK_PATTERN_AUTHENTICATION:
                    if (mResetLockPatternCommand != null) {
                        if (resultCode == Activity.RESULT_OK) {
                            String userId = mResetLockPatternCommand.getParams().optString(JSInterface.PARAM_JS_LOCK_PATTERN_USER_ID);
                            saveActivityResultHandler(REQUEST_CODE_RESET_LOCK_PATTERN, this);
                            getNavigator().navigateToCreateLockPatternScreen(WebViewTabFragment.this, userId, REQUEST_CODE_RESET_LOCK_PATTERN);
                        } else {
                            mResetLockPatternCommand.setResult(JSInterface.PARAM_NATIVE_LOCK_PATTERN_RESULT, getResult(resultCode));
                        }
                    }
                    return true;
                case REQUEST_CODE_RESET_LOCK_PATTERN:
                    if (mResetLockPatternCommand != null) {
                        mResetLockPatternCommand.setResult(JSInterface.PARAM_NATIVE_LOCK_PATTERN_RESULT, getResult(resultCode));
                    }
                    return true;
            }
            return false;
        }

    }

    private String getResult(int resultCode) {
        return resultCode == Activity.RESULT_OK ? "success" : "fail";
    }

    /**
     * Custom photo handler for the editor.  The inner listener that this creates also has a
     * reference to the editor and acts as an {@link }, and uses that editor to hold
     * state information in several of the listener methods.
     */
    private final class PhotoHandler extends PhotoSelectionHandler {

        private final PhotoActionListener mPhotoEditorListener;

        public PhotoHandler(Context context) {
            super(context);
            mPhotoEditorListener = new PhotoEditorListener();
        }

        @Override
        public PhotoActionListener getListener() {
            return mPhotoEditorListener;
        }

        @Override
        public void startPhotoActivity(Intent intent, int requestCode, Uri photoUri) {
            mCurrentPhotoUri = photoUri;
            saveActivityResultHandler(requestCode, this);
            WebViewTabFragment.this.startActivityForResult(intent, requestCode);
        }

        private final class PhotoEditorListener extends PhotoActionListener
                implements JSInterface.WebActionListener {

            private static final boolean DEFAULT_PHOTO_CROP_MODE = false;
            private static final int DEFAULT_MAX_PHOTO_COUNT = 9;
            private boolean mIsPhotoNeedCrop = DEFAULT_PHOTO_CROP_MODE;
            private int mMaxPhotoCount = DEFAULT_MAX_PHOTO_COUNT;
            private JSBridge.Command mCommand;

            @Override
            public void onRequest(JSBridge.Command cmd) {
                mCommand = cmd;
                if (JSInterface.REQUEST_JS_CHOOSE_IMAGE.equals(cmd.getName())) {
                    parseChooseImageParams(cmd);
                    onClick(webView);
                }
            }

            private void parseChooseImageParams(JSBridge.Command cmd) {
                mIsPhotoNeedCrop = isPhotoNeedCrop(cmd);
                if (mIsPhotoNeedCrop) {
                    mMaxPhotoCount = 1;
                } else {
                    mMaxPhotoCount = getMaxPhotoCount(cmd);
                }
            }

            private int getMaxPhotoCount(JSBridge.Command cmd) {
                return cmd.getParams().optInt(JSInterface.PARAM_JS_IMAGE_MAX_SELECTED_COUNT, DEFAULT_MAX_PHOTO_COUNT);
            }

            private boolean isPhotoNeedCrop(JSBridge.Command cmd) {
                return cmd.getParams().optInt(JSInterface.PARAM_JS_IMAGE_IS_HEAD_PORTRAIT, 0) == JSInterface.VALUE_JS_IS_HEAD_PORTRAIT_TRUE;
            }

            @Override
            public void onPhotoSelected(Uri uri) throws FileNotFoundException {
                if (mIsPhotoNeedCrop) {
                    mCommand.setResult(getHeadPortrait(uri));
                } else {
                    List<Uri> uriList = new ArrayList<>();
                    uriList.add(uri);
                    mCommand.setResult(getEncodedImagesJson(getEncodedImageList(uriList)));
                }
            }

            @Override
            public void onMultiPhotoSelected(final List<Uri> uriList) throws FileNotFoundException {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        final String result = getEncodedImagesJson(getEncodedImageList(uriList));
                        getActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mCommand.setResult(result);
                            }
                        });
                    }
                }).start();
            }

            @Override
            public boolean isPhotoNeedCrop() {
                return mIsPhotoNeedCrop;
            }

            @Override
            public int getMaxPhotoCount() {
                return mMaxPhotoCount;
            }

            private String getHeadPortrait(Uri uri) throws FileNotFoundException {
                final Bitmap bitmap = PhotoUtils.getBitmapFromUri(mContext, uri);
                String encodedImage = PhotoUtils.getHeadPortraitBase64FromBitmap(bitmap);
                List<String> list = new ArrayList<>();
                list.add(encodedImage);
                return getEncodedImagesJson(list);
            }

            private String getEncodedImagesJson(List<String> list) {
                EncodedImages encodedImages = new EncodedImages();
                encodedImages.setLocalIds(list);
                Gson gson = new Gson();
                return gson.toJson(encodedImages);
            }

            private List<String> getEncodedImageList(List<Uri> uriList) {
                List<String> imageList = new ArrayList<>();
                for (Uri uri : uriList) {
                    String encodedImage = PhotoUtils.getNormalImageBase64FromPhotoUri(getActivity(), uri);
                    imageList.add(encodedImage);
                }
                return imageList;
            }

            @Override
            public Uri getCurrentPhotoUri() {
                return mCurrentPhotoUri;
            }

            @Override
            public void onPhotoSelectionDismissed() {
                // Nothing to do.
            }
        }
    }

    private class EncodedImages {

        @SerializedName(JSInterface.PARAM_NATIVE_LOCAL_IDS)
        private List<String> localIds;

        public void setLocalIds(List<String> localIds) {
            this.localIds = localIds;
        }

        public List<String> getLocalIds() {
            return localIds;
        }
    }

    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     * <p/>
     * See the Android Training lesson <a href=
     * "http://developer.android.com/training/basics/fragments/communicating.html"
     * >Communicating with Other Fragments</a> for more information.
     */
    public interface OnFragmentInteractionListener {
        void setNavigationTitle(final String title);

        void showBottomTabWidget(final boolean show);

        void hideNavBackItem();

        void showNavBackItem();

        void hideOptionMenu();

        void showOptionMenu();

        void setCurrentTab(int position);
    }

}
